/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.mzk.oai.metadataRepository.repository.xmlConfiguration;

import cz.mzk.kramerius.commons.Dom4jUtils;
import cz.mzk.oai.metadataRepository.metadata.MetadataFormat;
import cz.mzk.oai.metadataRepository.repository.OaiSet;
import cz.mzk.oai.metadataRepository.repository.collections.MetadataCollection;
import cz.mzk.oai.metadataRepository.transformation.XsltConfig;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;

/**
 *
 * @author Martin Rehanek (rehan at mzk.cz)
 */
public class ConfigurationLoader {

    private static final Logger logger = Logger.getLogger(ConfigurationLoader.class.getName());
    //loaded configuration
    private Set<SetConfig> setConfigs;
    private Set<CollectionConfig> collectionConfigs;
    //temporary objects
    private Map<Integer, OaiSet> idSetMap = new HashMap<Integer, OaiSet>();
    private final Map<File, String> usedMetadataDirs = new HashMap<File, String>();
    //objects created from configuration
    private Set<OaiSet> oaiSets;
    private Set<MetadataCollection> collections;

    public ConfigurationLoader(File collectionAndSetsConfigurationXml) throws IOException, DocumentException {
        Document configDoc = Dom4jUtils.loadDocument(collectionAndSetsConfigurationXml, false);
        processConfig(configDoc);
        createOaiSets();
        createMetadataCollections();
    }

    private void processConfig(Document configDoc) throws DocumentException {
        SetConfigLoader setLoader = new SetConfigLoader(configDoc);
        setConfigs = setLoader.getResults();
        CollectionConfigLoader collectionLoader = new CollectionConfigLoader(configDoc);
        collectionConfigs = collectionLoader.getResults();
//        printSetConfigs();
//        printCollectionConfigs();
    }

    private void printSetConfigs() {
        System.out.println("SetConfigs:");
        for (SetConfig setConfig : setConfigs) {
            System.out.println(setConfig);
        }
    }

    private void printCollectionConfigs() {
        System.out.println("CollectionConfigs:");
        for (CollectionConfig collection : collectionConfigs) {
            System.out.println(collection);
        }
    }

    public Set<MetadataCollection> getCollections() {
        return collections;
    }

    public Set<OaiSet> getSets() {
        return oaiSets;
    }

    private void createOaiSets() {
        oaiSets = new HashSet<OaiSet>();
        for (SetConfig setConfig : setConfigs) {
            OaiSet oaiSet = new OaiSet(setConfig.getSpec(), setConfig.getName());
            oaiSets.add(oaiSet);
            idSetMap.put(setConfig.getId(), oaiSet);
        }
    }

    private void createMetadataCollections() throws DocumentException, IOException {
        collections = new HashSet<MetadataCollection>();
        for (CollectionConfig collectionConfig : collectionConfigs) {
            MetadataCollection collection = createCollection(collectionConfig);
            addCollectionToSets(collection);
            collections.add(collection);
        }
    }

    private MetadataCollection createCollection(CollectionConfig collectionConfig) throws DocumentException, IOException {
        String alephBase = collectionConfig.getAlephBase();
        String name = collectionConfig.getName();
        File rootDir = collectionConfig.getMetadataDir();
        checkIfMetadataDirNotPresent(rootDir, name);
        Set<OaiSet> setsOfCollection = findSets(collectionConfig.getSetIds());
        Set<MetadataFormat> formats = collectionConfig.getMetadataFormats();
        Set<XsltConfig> xsltConfigs = collectionConfig.getTransformationConfigs();
        boolean itemsCanBeMoved = collectionConfig.itemsCanBeTransfered();
        return new MetadataCollection(alephBase, name, rootDir, formats, setsOfCollection, xsltConfigs, itemsCanBeMoved);
    }

    private void checkIfMetadataDirNotPresent(File metadataDir, String collectionName) {
        String foundCollection = usedMetadataDirs.get(metadataDir);
        if (foundCollection != null) {
            logger.log(Level.WARNING, "Metadata dir {0} allready used for {1}. Trying to assign it to {2}", new Object[]{metadataDir.getAbsolutePath(), foundCollection, collectionName});
        } else {
            usedMetadataDirs.put(metadataDir, collectionName);
        }
    }

    private Set<OaiSet> findSets(Set<Integer> setIds) throws DocumentException {
        Set<OaiSet> result = new HashSet<OaiSet>(setIds.size());
        for (Integer setId : setIds) {
            result.add(findOaiSetByConfigIdIfPresent(setId));
        }
        return result;
    }

    private OaiSet findOaiSetByConfigIdIfPresent(Integer setId) throws DocumentException {
        OaiSet oaiSet = idSetMap.get(setId);
        if (oaiSet == null) {
            throw new DocumentException("there's no set with id " + setId.toString());
        }
        return oaiSet;
    }

    private void addCollectionToSets(MetadataCollection collection) {
        for (OaiSet oaiSet : collection.getOaiSets()) {
            oaiSet.addCollection(collection);
        }
    }
}
